home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / manchest.lha / MANCHESTER / manchester / 2.2 / Printed-circuits.st < prev    next >
Text File  |  1993-07-24  |  48KB  |  1,698 lines

  1. "    NAME        Printed-circuits
  2.     AUTHOR        tph@cs.man.ac.uk
  3.     FUNCTION simple cct board editor 
  4.     ST-VERSIONS    2.2
  5.     PREREQUISITES     
  6.     CONFLICTS    
  7.     DISTRIBUTION      world
  8.     VERSION        1.1
  9.     DATE    22 Jan 1989
  10. SUMMARY    Printed-circuits
  11.     is an implementation of a simple printed circuit
  12.    board editor.(2.2).TPH
  13. "!
  14. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:24:31 pm'!
  15.  
  16. SequenceableCollection removeSelector: #size!
  17. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:22:50 pm'!
  18.  
  19.  
  20. !Interval reorganize!
  21. ('comparing' = hash hashMappedBy:)
  22. ('accessing' at: at:put: first increment last size)
  23. ('adding' add:)
  24. ('removing' remove:)
  25. ('copying' copy)
  26. ('testing' includes:)
  27. ('enumerating' collect: do: reverseDo:)
  28. ('printing' printOn: storeOn:)
  29. ('private' setFrom:to:by: species)
  30. !
  31.  
  32.  
  33.  
  34. !Interval methodsFor: 'accessing'!
  35.  
  36. size
  37.     (self isKindOf: Number) ifFalse: [^super size].
  38.     step < 0
  39.         ifTrue: [start < stop
  40.                 ifTrue: [^0]
  41.                 ifFalse: [^stop - start // step + 1]]
  42.         ifFalse: [stop < start
  43.                 ifTrue: [^0]
  44.                 ifFalse: [^stop - start // step + 1]]! !
  45.  
  46. !Interval methodsFor: 'testing'!
  47.  
  48. includes: aNumber
  49.     "Answer whether aNumber is one of the receiver's elements.
  50.      Re-implemented here to gain some performance."
  51.  
  52.     (aNumber isKindOf: Number) ifFalse: [^super includes: aNumber].
  53.     (aNumber < start or: [aNumber > stop]) ifTrue: [^false].
  54.     ^(aNumber - start) isMultipleOf: step! !
  55. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:25:00 pm'!
  56.  
  57.  
  58.  
  59. !Number methodsFor: 'testing'!
  60.  
  61. isMultipleOf: aNumber 
  62.     "Answers true if the receiver is an exact multiple of 
  63.      aNumber, otherwise false."
  64.  
  65.     ^self \\ aNumber = 0!
  66.  
  67. notMultipleOf: aNumber 
  68.     "Answers false if the receiver is an exact multiple of 
  69.      aNumber, otherwise true."
  70.  
  71.     ^(self isMultipleOf: aNumber) not! !
  72. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:32:40 pm'!
  73.  
  74.  
  75.  
  76. !Point methodsFor: 'truncation and round off'!
  77.  
  78. truncated
  79.     "Answer a new Point that is the receiver's x and y truncated."
  80.  
  81.     ^x truncated @ y truncated! !
  82.  
  83. !Point methodsFor: 'point functions'!
  84.  
  85. nearestTo45DegreeLineThrough: refPoint onGrid: aGridPoint
  86.     "Answers the closest integer point to the receiver which
  87.      is both on the grid given by aGridPoint and on a
  88.      45 degree line through refPoint."
  89.  
  90.     | thePoints currentDistance shortestDistance closestPoint |
  91.  
  92.     " Generate the four nearest points on lines through refPoint. "
  93.     thePoints _ OrderedCollection new.
  94.     (Array with: 1@0 with: 1@1 with: 0@1 with: -1@1) do: [
  95.         :aSlope | thePoints add: (self pointNearestLine: refPoint to: refPoint + aSlope)].
  96.  
  97.     " Generate the four distances from the nearest points on the line to aPoint,
  98.         find the shortest one, and thus the closest point. "
  99.     shortestDistance _ 1000000.
  100.     thePoints do:
  101.         [:eachPoint | currentDistance _ self dist: eachPoint.
  102.                 (currentDistance <= shortestDistance ifTrue: [closestPoint _ eachPoint.
  103.                                                         shortestDistance _ currentDistance])
  104.         ].
  105.     ^closestPoint grid: aGridPoint!
  106.  
  107. pointNearestLine: point1 to: point2
  108.     "Answers the closest integer point to the receiver on the
  109.      line determined by (point1, point2)."
  110.  
  111.     | relPoint delta |
  112.     delta _ point2 - point1.             "normalize coordinates"
  113.     relPoint _ self - point1.
  114.     delta x = 0 ifTrue: [^point1 x@y].
  115.     delta y = 0 ifTrue: [^x@point1 y].
  116.     delta x abs > delta y abs         "line more horizontal?"
  117.         ifTrue: [^x@(point1 y + (x * delta y // delta x))]
  118.         ifFalse: [^(point1 x + (relPoint y * delta x // delta y))@y]
  119.  
  120.     "43@55 pointNearestLine: 10@10 to: 100@200"! !
  121. Point removeSelector: #truncatedGrid:!
  122. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:33:01 pm'!
  123.  
  124.  
  125.  
  126. !Rectangle methodsFor: 'truncation and round off'!
  127.  
  128. truncated
  129.     "Answer a Rectangle whose origin and corner are truncated."
  130.  
  131.     ^Rectangle origin: origin truncated corner: corner truncated! !
  132. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:34:24 pm'!
  133.  
  134. Point subclass: #PcbObject
  135.     instanceVariableNames: ''
  136.     classVariableNames: ''
  137.     poolDictionaries: ''
  138.     category: 'Printed-Circuits'!
  139. PcbObject comment:
  140. 'I am the abstract superclass of objects which appear on a printed circuit
  141. board.  Instance variables x and y (inherited from Point) indicate the
  142. location of my instances.
  143. '!
  144.  
  145.  
  146. !PcbObject methodsFor: 'accessing'!
  147.  
  148. refPoint
  149.     "Answer with my reference point."
  150.  
  151.     ^self x@self y!
  152.  
  153. refX
  154.     "Answer with my reference x value."
  155.  
  156.     ^self x!
  157.  
  158. refY
  159.     "Answer with my reference y value."
  160.  
  161.     ^self y!
  162.  
  163. size
  164.     "Answer with a value representing my size (for sorting purposes)."
  165.  
  166.     self subclassResponsibility! !
  167.  
  168. !PcbObject methodsFor: 'file handling'!
  169.  
  170. writeBottomDrawerOn: aFileStream
  171.     "Write the closest possible representation of the receiver
  172.      in bottom drawer format on aFileStream."
  173.  
  174.     aFileStream nextPutAll: '/ '.
  175.     aFileStream nextPutAll: self asBottomDrawer.
  176.     aFileStream nextPutAll: ' //'.
  177.     aFileStream lf! !
  178. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  179.  
  180. PcbObject class
  181.     instanceVariableNames: ''!
  182.  
  183.  
  184. !PcbObject class methodsFor: 'private'!
  185.  
  186. getIntegerFrom: aFileStream 
  187.     "Gets a sequence of 1 or more digit characters from 
  188.      aFileStream, terminated by any non-digit. Answer the 
  189.      corresponding integer."
  190.  
  191.     | aChar anInteger |
  192.     anInteger _ 0.
  193.     aChar _ aFileStream next.
  194.     [aChar isDigit] whileFalse: [aChar _ aFileStream next].
  195.     [aChar isDigit] whileTrue: [
  196.             anInteger _ anInteger * 10 + aChar digitValue.
  197.             aChar _ aFileStream next].
  198.     ^anInteger!
  199.  
  200. getSlashFrom: aFileStream
  201.     "Gets a Slash character from aFileStream."
  202.  
  203.     | aChar |
  204.     aChar _ aFileStream next.
  205.     [aChar = $/] whileFalse: [aChar _ aFileStream next].
  206.     ^aChar! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:34:48 pm'!
  207.  
  208. PcbObject subclass: #Pad
  209.     instanceVariableNames: 'diameter '
  210.     classVariableNames: 'DefaultDiameter PadSlide '
  211.     poolDictionaries: ''
  212.     category: 'Printed-Circuits'!
  213. Pad comment:
  214. 'I represent a Pad (component fixing) on a printed circuit board.
  215. I add an instance variable diameter, indicating my size.
  216. '!
  217.  
  218.  
  219. !Pad methodsFor: 'accessing'!
  220.  
  221. diameter
  222.     "Answer with the diameter of the receiver."
  223.  
  224.     ^diameter!
  225.  
  226. diameter: aNumber
  227.     "Set the diameter of the receiver."
  228.  
  229.     diameter _ aNumber!
  230.  
  231. position
  232.     "Answers a point equal to current position of the receiver."
  233.  
  234.     ^self x@self y!
  235.  
  236. size
  237.     "Answer with my diameter"
  238.  
  239.     ^diameter! !
  240.  
  241. !Pad methodsFor: 'testing'!
  242.  
  243. isZeroDiameter
  244.     "Answer whether the receiver has a diameter of zero."
  245.  
  246.     ^self diameter = 0! !
  247.  
  248. !Pad methodsFor: 'comparing'!
  249.  
  250. = anObject
  251.     "Answer whether the receiver is the same as anObject."
  252.  
  253.     ^super = anObject and: [self diameter = anObject diameter]! !
  254.  
  255. !Pad methodsFor: 'truncation and rounding'!
  256.  
  257. rounded
  258.     "Answer with a new Pad that is a rounded version of the receiver."
  259.  
  260.     ^Pad point: super rounded diameter: (self diameter rounded max: 1)!
  261.  
  262. truncated
  263.     "Answer with a new Pad that is a truncated version of the receiver."
  264.  
  265.     ^Pad
  266.         x: self x rounded
  267.         y: self y rounded
  268.         diameter: (self diameter truncated max: 1)! !
  269.  
  270. !Pad methodsFor: 'transforming'!
  271.  
  272. scaleBy: aPoint 
  273.     "Answer a new Pad scaled by aPoint"
  274.  
  275.     ^Pad
  276.         point: (super scaleBy: aPoint)
  277.         diameter: self diameter * (aPoint x min: aPoint y)!
  278.  
  279. translateBy: delta 
  280.     "Answer a new Pad translated by delta."
  281.  
  282.     ^Pad
  283.         point: (super translateBy: delta)
  284.         diameter: self diameter! !
  285.  
  286. !Pad methodsFor: 'point functions'!
  287.  
  288. grid: aPoint
  289.     "Answer with a new Pad, with the endpoints rounded
  290.      to a grid given by aPoint."
  291.  
  292.     ^Pad point: (super grid: aPoint) diameter: self diameter! !
  293.  
  294. !Pad methodsFor: 'printing'!
  295.  
  296. printOn: aStream 
  297.     "The receiver prints on aStream in terms of infix notation."
  298.  
  299.     x printOn: aStream.
  300.     aStream nextPut: $@.
  301.     y printOn: aStream.
  302.     aStream nextPutAll: ' dia '.
  303.     diameter printOn: aStream.! !
  304.  
  305. !Pad methodsFor: 'file handling'!
  306.  
  307. asBottomDrawer
  308.     "Answers with a string which is the closest Bottom Drawer 
  309.      representation of the receiver."
  310.  
  311.     ^(self bottomDrawerPadSize: self diameter), ' X' ,
  312.         self x printString, ' Y', self y printString! !
  313.  
  314. !Pad methodsFor: 'private'!
  315.  
  316. bottomDrawerPadSize: aDiameter 
  317.     "Answers a String with the nearest Bottom Drawer Pad size to 
  318.     aDiameter. "
  319.  
  320.     PadSlide associationsDo: [:assoc |
  321.         (assoc value includes: aDiameter) ifTrue: [^assoc key asString]].
  322.     ^self error: 'Diameter outside range of Pad sizes for the current slide.'!
  323.  
  324. setX: xPad setY: yPad setDiameter: diameterPad
  325.     "Set up the x, y and diameter for the receiver."
  326.  
  327.      x _ xPad.
  328.     y _ yPad.
  329.     diameter _ diameterPad! !
  330. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  331.  
  332. Pad class
  333.     instanceVariableNames: ''!
  334.  
  335.  
  336. !Pad class methodsFor: 'instance creation'!
  337.  
  338. bottomDrawerPadFrom: aFileStream 
  339.     "Gets a BottomDrawer Pad representation from aFileStream.  
  340.      Answers the corresponding Pad."
  341.  
  342.     | anInterval size aPad |
  343.     anInterval _ PadSlide at: ('P', (self getIntegerFrom: aFileStream) printString) asSymbol.
  344.     aPad _ self
  345.                 x: (self getIntegerFrom: aFileStream)
  346.                 y: (self getIntegerFrom: aFileStream)
  347.                 diameter: anInterval first + anInterval last // 2.
  348.     self getSlashFrom: aFileStream.
  349.     self getSlashFrom: aFileStream.        " Discard double slash"
  350.     aFileStream next.                    " Discard lf"
  351.     ^aPad!
  352.  
  353. point: aPoint 
  354.     "Answer a new instance of me with coordinates given 
  355.      by the point aPoint, and diameter equal to the DefaultDiameter."
  356.  
  357.     ^self
  358.         point: aPoint
  359.         diameter: DefaultDiameter!
  360.  
  361. point: aPoint diameter: aNumber
  362.     "Answer a new instance of me with coordinates given 
  363.      by the point aPoint, and diameter equal to aNumber."
  364.  
  365.     ^self
  366.         x: aPoint x
  367.         y: aPoint y
  368.         diameter: aNumber!
  369.  
  370. x: xInteger y: yInteger 
  371.     "Answer a new instance of me with coordinates xInteger 
  372.      and yInteger, and diameter equal to the DefaultDiameter."
  373.  
  374.     ^self
  375.         x: xInteger
  376.         y: yInteger
  377.         diameter: DefaultDiameter!
  378.  
  379. x: xInteger y: yInteger diameter: diameterInteger 
  380.     "Answer a new instance of me with coordinates xInteger 
  381.      and yInteger, diameter diameterInteger."
  382.  
  383.     ^self new
  384.         setX: xInteger
  385.         setY: yInteger
  386.         setDiameter: diameterInteger! !
  387.  
  388. !Pad class methodsFor: 'class initialization'!
  389.  
  390. initialize.
  391.     "Initialize class variables."
  392.     "Pad initialize."
  393.  
  394.     DefaultDiameter _ 60.   "Default Pad diameter"
  395.  
  396.     PadSlide _ Dictionary new.        " EMMA Pad Slide"
  397.     PadSlide at: #P1 put: (Interval from: 0 to: 7).            " Nominal 5 thou "
  398.     PadSlide at: #P2 put: (Interval from: 8 to: 12).            " Nominal 10 thou "
  399.     PadSlide at: #P3 put: (Interval from: 13 to: 17).        " Nominal 15 thou "
  400.     PadSlide at: #P4 put: (Interval from: 18 to: 22).        " Nominal 20 thou "
  401.     PadSlide at: #P5 put: (Interval from: 23 to: 29).        " Nominal 25 thou "
  402.     PadSlide at: #P6 put: (Interval from: 30 to: 35).        " Nominal 32 thou "
  403.     PadSlide at: #P7 put: (Interval from: 36 to: 45).        " Nominal 37 thou "
  404.     PadSlide at: #P8 put: (Interval from: 46 to: 55).        " Nominal 50 thou "
  405.     PadSlide at: #P9 put: (Interval from: 56 to: 68).        " Nominal 60 thou "
  406.     PadSlide at: #P10 put: (Interval from: 69 to: 77).        " Nominal 75 thou "
  407.     PadSlide at: #P11 put: (Interval from: 78 to: 90).        " Nominal 80 thou "
  408.     PadSlide at: #P12 put: (Interval from: 91 to: 112).        " Nominal 100 thou "
  409.     PadSlide at: #P13 put: (Interval from: 113 to: 137).    " Nominal 125 thou "
  410.     PadSlide at: #P14 put: (Interval from: 138 to: 175).    " Nominal 150 thou "
  411.     PadSlide at: #P15    put: (Interval from: 176 to: 10000). "Nominal 200 thou "! !
  412.  
  413. !Pad class methodsFor: 'class access'!
  414.  
  415. defaultDiameter
  416.     "Answer with the default pad size."
  417.  
  418.     ^DefaultDiameter! !
  419.  
  420. Pad initialize!
  421. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:35:14 pm'!
  422.  
  423. PcbObject subclass: #TrackSegment
  424.     instanceVariableNames: 'endX endY width '
  425.     classVariableNames: 'DefaultWidth TrackSlide '
  426.     poolDictionaries: ''
  427.     category: 'Printed-Circuits'!
  428. TrackSegment comment:
  429. 'I represent a segment of a track on a printed circuit board.  I add
  430. instance variables indicating my end point (endX, endY) and my
  431. size (width).
  432. '!
  433.  
  434.  
  435. !TrackSegment methodsFor: 'accessing'!
  436.  
  437. endPoint
  438.     "Answers a point corresponding to the end of the receiver."
  439.  
  440.     ^self x2 @ self y2!
  441.  
  442. size
  443.     "Answer with my width."
  444.  
  445.     ^width!
  446.  
  447. startPoint
  448.     "Answers a point corresponding to the start of the receiver."
  449.  
  450.     ^self x1 @ self y1!
  451.  
  452. width
  453.     "Answer with the track width."
  454.  
  455.     ^width!
  456.  
  457. x1
  458.     "Answer with the starting x coordinate."
  459.  
  460.     ^x!
  461.  
  462. x2
  463.     "Answer with the end x coordinate."
  464.  
  465.     ^endX!
  466.  
  467. y1
  468.     "Answer with the starting y coordinate."
  469.  
  470.     ^y!
  471.  
  472. y2
  473.     "Answer with the end y coordinate."
  474.  
  475.     ^endY! !
  476.  
  477. !TrackSegment methodsFor: 'testing'!
  478.  
  479. isZeroLength
  480.     "Answer whether the receiver is of zero Length."
  481.  
  482.     ^self startPoint = self endPoint! !
  483.  
  484. !TrackSegment methodsFor: 'comparing'!
  485.  
  486. = aTrackSegment 
  487.     "Answer whether the receiver is equal to aTrackSegment."
  488.  
  489.     self species = aTrackSegment species
  490.         ifTrue: [^(self sameWidthAs: aTrackSegment)
  491.                 and: [self sameLineAs: aTrackSegment]]
  492.         ifFalse: [^false]!
  493.  
  494. sameEndAs: aTrackSegment
  495.     "Answer whether the reciver has the same end value
  496.      as aTrackSegment."
  497.  
  498.     ^self x2 = aTrackSegment x2 and: [self y2 = aTrackSegment y2]!
  499.  
  500. sameLineAs: aTrackSegment
  501.     "Answer whether the reciver has the same start and end points as
  502.      aTrackSegment."
  503.  
  504.     ^(self sameStartAs: aTrackSegment) and: [self sameEndAs: aTrackSegment]!
  505.  
  506. sameStartAs: aTrackSegment
  507.     "Answer whether the reciver has the same starting value
  508.      as aTrackSegment."
  509.  
  510.     ^self x1 = aTrackSegment x1 and: [self y1 = aTrackSegment y1]!
  511.  
  512. sameWidthAs: aTrackSegment
  513.     "Answer whether the receiver has the same width as aTrackSegment."
  514.  
  515.     ^self width = aTrackSegment width! !
  516.  
  517. !TrackSegment methodsFor: 'truncation and rounding'!
  518.  
  519. rounded
  520.     "Answer with a new TrackSegment that is a rounded version 
  521.      of the receiver."
  522.  
  523.     ^TrackSegment
  524.         from: self startPoint rounded
  525.         to: self endPoint rounded
  526.         width: (self width rounded max: 1)!
  527.  
  528. truncated
  529.     "Answer with a new TrackSegment that is a truncated version 
  530.      of the receiver."
  531.  
  532.     ^TrackSegment
  533.         from: (self startPoint truncateTo: 1@1)
  534.         to: (self endPoint truncateTo: 1@1)
  535.         width: (self width truncated max: 1)! !
  536.  
  537. !TrackSegment methodsFor: 'transforming'!
  538.  
  539. scaleBy: aPoint 
  540.     "Answer a new TrackSegment scaled by aPoint."
  541.  
  542.     ^TrackSegment
  543.         from: (self startPoint scaleBy: aPoint)
  544.         to: (self endPoint scaleBy: aPoint)
  545.         width: self width * (aPoint x min: aPoint y)!
  546.  
  547. translateBy: delta 
  548.     "Answer with a new TrackSegment translated by delta."
  549.  
  550.     ^TrackSegment
  551.         from: (self startPoint translateBy: delta)
  552.         to: (self endPoint translateBy: delta)
  553.         width: self width! !
  554.  
  555. !TrackSegment methodsFor: 'point functions'!
  556.  
  557. grid: aPoint 
  558.     "Answer with a new TrackSegment, with the endpoints 
  559.      rounded to a grid given by aPoint."
  560.  
  561.     ^TrackSegment
  562.         from: (self startPoint grid: aPoint)
  563.         to: (self endPoint grid: aPoint)
  564.         width: self width! !
  565.  
  566. !TrackSegment methodsFor: 'printing'!
  567.  
  568. printOn: aStream 
  569.     "The receiver prints on aStream in terms of infix notation."
  570.  
  571.     self x1 printOn: aStream.
  572.     aStream nextPut: $@.
  573.     self y1 printOn: aStream.
  574.     aStream nextPutAll: ' to '.
  575.     self x2 printOn: aStream.
  576.     aStream nextPut: $@.
  577.     self y2 printOn: aStream.
  578.     aStream nextPutAll: ' width '.
  579.     self width printOn: aStream.! !
  580.  
  581. !TrackSegment methodsFor: 'file handling'!
  582.  
  583. asBottomDrawer
  584.     "Answers with a string which is the closest Bottom Drawer 
  585.      representation to the receiver."
  586.  
  587.     ^'X', self x1 printString, ' Y', self y1 printString, ' ',
  588.         (self bottomDrawerTrackSize: self width),
  589.         ' X', self x2 printString , ' Y', self y2 printString! !
  590.  
  591. !TrackSegment methodsFor: 'private'!
  592.  
  593. bottomDrawerTrackSize: aTrackWidth 
  594.     "Answers a String with the nearest Bottom Drawer Track size to 
  595.     aTrackWidth. "
  596.  
  597.     TrackSlide associationsDo: [:assoc |
  598.         (assoc value includes: aTrackWidth) ifTrue: [^assoc key asString]].
  599.     ^self error: 'Diameter outside range of Track sizes for the current slide.'!
  600.  
  601. setX1: x1 setY1: y1 setX2: x2 setY2: y2 setWidth: trackWidth 
  602.     "If the first point is above and to the left of the second point, 
  603.      set the instance variables as given.  Otherwise, reverse the 
  604.      order of the points."
  605.  
  606.     (x1 < x2 and: [y1 < y2])
  607.         ifTrue: [
  608.             x _ x1.  endX _ x2.
  609.             y _ y1.  endY _ y2]
  610.         ifFalse: [
  611.             x _ x2.  endX _ x1.
  612.             y _ y2.  endY _ y1].
  613.     width _ trackWidth! !
  614. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  615.  
  616. TrackSegment class
  617.     instanceVariableNames: ''!
  618.  
  619.  
  620. !TrackSegment class methodsFor: 'instance creation'!
  621.  
  622. bottomDrawerTrackFrom: aFileStream 
  623.     "Gets a Bottom Drawer Track representation from aFileStream 
  624.      Answers the corresponding Track Segment"
  625.  
  626.     | anInterval x1 y1 aTrackSegment |
  627.     x1 _ self getIntegerFrom: aFileStream.
  628.     y1 _ self getIntegerFrom: aFileStream.
  629.     anInterval _ TrackSlide at:
  630.         ('L' , (self getIntegerFrom: aFileStream) printString) asSymbol.
  631.     aTrackSegment _ self
  632.                 x1: x1
  633.                 y1: y1
  634.                 x2: (self getIntegerFrom: aFileStream)
  635.                 y2: (self getIntegerFrom: aFileStream)
  636.                 width: anInterval first + anInterval last // 2.
  637.     self getSlashFrom: aFileStream.
  638.     self getSlashFrom: aFileStream.        " Discard double slash"
  639.     aFileStream next.                    " Discard lf"
  640.     ^aTrackSegment!
  641.  
  642. from: point1 to: point2 
  643.     "Answer a new instance of me with endpoints given by point1 
  644.      and point2, and width equal to the default width."
  645.  
  646.     ^self
  647.         x1: point1 x
  648.         y1: point1 y
  649.         x2: point2 x
  650.         y2: point2 y
  651.         width: DefaultWidth!
  652.  
  653. from: point1 to: point2 width: widthInteger 
  654.     "Answer a new instance of me with endpoints given by point1  
  655.      and point2, and width equal to widthInteger."
  656.  
  657.     ^self
  658.         x1: point1 x
  659.         y1: point1 y
  660.         x2: point2 x
  661.         y2: point2 y
  662.         width: widthInteger!
  663.  
  664. x1: x1 y1: y1 x2: x2 y2: y2 
  665.     "Answer a new instance of me with endpoints (x1,y1), (x2,y2), with 
  666.      the default width."
  667.  
  668.     ^self
  669.         x1: x1
  670.         y1: y1
  671.         x2: x2
  672.         y2: y2
  673.         width: DefaultWidth!
  674.  
  675. x1: x1 y1: y1 x2: x2 y2: y2 width: widthInteger 
  676.     "Answer a new instance of me with endpoints (x1,y1), (x2,y2),  
  677.      with width given by widthInteger."
  678.  
  679.     ^self new
  680.         setX1: x1
  681.         setY1: y1
  682.         setX2: x2
  683.         setY2: y2
  684.         setWidth: widthInteger! !
  685.  
  686. !TrackSegment class methodsFor: 'class initialization'!
  687.  
  688. initialize
  689.     "Initialize class variables."
  690.     "TrackSegment initialize."
  691.  
  692.     DefaultWidth _ 20.   "Default Track Width"
  693.  
  694.     TrackSlide _ Dictionary new.        "EMMA Track slide"
  695.     TrackSlide at: #L1 put: (Interval from: 0 to: 7).        " Nominal 5 thou "
  696.     TrackSlide at: #L2 put: (Interval from: 8 to: 15).        " Nominal 10 thou "
  697.     TrackSlide at: #L3 put: (Interval from: 16 to: 26).        " Nominal 20 thou "
  698.     TrackSlide at: #L4 put: (Interval from: 27 to: 34).        " Nominal 32 thou "
  699.     TrackSlide at: #L5 put: (Interval from: 35 to: 45).        " Nominal 37 thou "
  700.     TrackSlide at: #L6 put: (Interval from: 46 to: 55).        " Nominal 50 thou "
  701.     TrackSlide at: #L7 put: (Interval from: 56 to: 70).        " Nominal 60 thou "
  702.     TrackSlide at: #L8 put: (Interval from: 71 to: 90).        " Nominal 80 thou "
  703.     TrackSlide at: #L9 put: (Interval from: 15 to: 25).        " Nominal 20 thou "
  704.     TrackSlide at: #L12 put: (Interval from: 91 to: 125).    " Nominal 100 thou "
  705.     TrackSlide at: #L14 put: (Interval from: 126 to: 175).    " Nominal 150 thou "
  706.     TrackSlide at: #L15 put: (Interval from: 176 to: 225).    " Nominal 200 thou "
  707.     TrackSlide at: #L16 put: (Interval from: 226 to: 100000). " Anything larger!!"! !
  708.  
  709. !TrackSegment class methodsFor: 'class access'!
  710.  
  711. defaultWidth
  712.     "Answer with the default track width."
  713.  
  714.     ^DefaultWidth! !
  715.  
  716. TrackSegment initialize!
  717. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:35:31 pm'!
  718.  
  719. Object subclass: #PrintedCircuit
  720.     instanceVariableNames: 'pads tracks grid '
  721.     classVariableNames: 'DefaultGrid '
  722.     poolDictionaries: ''
  723.     category: 'Printed-Circuits'!
  724. PrintedCircuit comment:
  725. 'I represent a printed circuit board.  I have instance variables:
  726.  
  727. tracks    A <Set> of the tracks making up this printed circuit board.
  728.  
  729. pads    A <Set> of the pads making up this board.
  730.  
  731. grid        A <Point> indicating the grid size of this printed circuit
  732.         board.  All Pads and TrackSegments are constrained to
  733.         lie on this grid.
  734. '!
  735.  
  736.  
  737. !PrintedCircuit methodsFor: 'initialize-release'!
  738.  
  739. initialize
  740.     "Initialize the pads and tracks of the receiver."
  741.  
  742.     tracks _ Set new.
  743.     pads _ Set new.
  744.     grid _ DefaultGrid!
  745.  
  746. release
  747.  
  748.     pads release.
  749.     tracks release.
  750.     grid release.
  751.     super release!
  752.  
  753. restart
  754.     "Discard the current contents of the receiver."
  755.  
  756.     self initialize.
  757.     self changed: #all! !
  758.  
  759. !PrintedCircuit methodsFor: 'accessing'!
  760.  
  761. grid
  762.     "Answer with the current grid (a Point)."
  763.  
  764.     ^grid!
  765.  
  766. grid: aPoint
  767.     "Set the current grid size."
  768.  
  769.     grid _ aPoint!
  770.  
  771. pads
  772.     "Answer with the set of pads."
  773.  
  774.     ^pads!
  775.  
  776. tracks
  777.     "Answer with the set of tracks."
  778.  
  779.     ^tracks! !
  780.  
  781. !PrintedCircuit methodsFor: 'adding'!
  782.  
  783. addPad: aPad
  784.     "Add aPad to the set of pads in the receiver, using the current
  785.      grid size.  Answer with the pad just added"
  786.  
  787.     ^self addPad: aPad onGrid: self grid!
  788.  
  789. addPad: aPad onGrid: aPoint
  790.     "Add aPad (rounded to the nearest grid point) to the set
  791.      of pads in the receiver.  Answer with the pad just    
  792.      inserted."
  793.  
  794.     | pad |
  795.     pad _ aPad grid: aPoint.
  796.     self pads add: pad.
  797.     ^pad!
  798.  
  799. addTrack: aTrack 
  800.     "Add aTrack to the set of tracks in the receiver.  Answer with
  801.      the track just added."
  802.  
  803.     ^self addTrack: aTrack onGrid: self grid!
  804.  
  805. addTrack: aTrack onGrid: aPoint
  806.     "Add aTrack (rounded to the nearest grid point) to the set
  807.      of tracks in the receiver.  Answer with the track just inserted."
  808.  
  809.     | track |
  810.     track _     aTrack grid: aPoint.
  811.     track isZeroLength ifTrue: [^nil] ifFalse: [self tracks add: track].
  812.     ^track! !
  813.  
  814. !PrintedCircuit methodsFor: 'removing'!
  815.  
  816. removePad: aPoint
  817.     "Remove the pad at aPoint from the receiver's list of pads."
  818.  
  819.     self pads remove: (self pads detect: [:each | aPoint = each position])!
  820.  
  821. removeTrackSegment: anArray
  822.     "Remove the TrackSegment indicated by anArray from the
  823.      receiver's list of tracks."
  824.  
  825.     | start end |
  826.     start _ anArray at: 1.
  827.     end _ anArray at: 2.
  828.     self tracks remove:
  829.         (self tracks detect: [:each |
  830.                 (start = each startPoint and: [end = each endPoint])
  831.              or: [start = each endPoint and: [end = each startPoint]]])! !
  832.  
  833. !PrintedCircuit methodsFor: 'file handling'!
  834.  
  835. bottomDrawerItemFrom: aFileStream 
  836.     "Gets a BottomDrawer Item representation from aFileStream. 
  837.      Adds the item returned to the appropriate set (tracks or pads)."
  838.  
  839.     | aChar |
  840.     aChar _ aFileStream next.
  841.     [aChar = $P | (aChar = $X)] whileFalse: [aChar _ aFileStream next].
  842.     aChar = $P ifTrue: [
  843.         self addPad: (Pad bottomDrawerPadFrom: aFileStream)].
  844.     aChar = $X ifTrue: [
  845.         self addTrack: (TrackSegment bottomDrawerTrackFrom: aFileStream)]!
  846.  
  847. readBottomDrawerFile: aFilename
  848.     "Initialize the receiver from the file indicated by aFilename."
  849.  
  850.     | file |
  851.     file _ FileStream fileNamed: aFilename.
  852.     file text.
  853.     file readOnly.
  854.     file reset.
  855.     Cursor read showWhile: [
  856.         [file atEnd] whileFalse: [self bottomDrawerItemFrom: file]].
  857.     file close.
  858.     self changed: #all!
  859.  
  860. writeBottomDrawerOn: aFilename 
  861.     "Writes a BottomDrawer representation of the receiver
  862.      on the named file."
  863.  
  864.     | file temp routeNumber |
  865.     file _ FileStream fileNamed: aFilename.
  866.     file text.
  867.     Cursor wait showWhile: [
  868.         temp _ self tracks asSortedCollection.
  869.         temp addAll: self pads].
  870.     routeNumber _ 0.
  871.     Cursor write showWhile: [
  872.         temp do: [:each |
  873.             routeNumber _ routeNumber + 1.
  874.             file nextPutAll: routeNumber printString.
  875.             each writeBottomDrawerOn: file]].
  876.     file close!
  877.  
  878. writeBottomDrawerPadsOn: aFilename 
  879.     "Writes a BottomDrawer representation of the receiver
  880.      (pads only) on the named file."
  881.  
  882.     | file temp routeNumber |
  883.     file _ FileStream fileNamed: aFilename.
  884.     file text.
  885.     Cursor wait showWhile: [temp _ self pads asSortedCollection].
  886.     routeNumber _ 0.
  887.     Cursor write showWhile: [
  888.         temp do: [:each |
  889.             routeNumber _ routeNumber + 1.
  890.             file nextPutAll: routeNumber printString.
  891.             each writeBottomDrawerOn: file]].
  892.     file close!
  893.  
  894. writeBottomDrawerTracksOn: aFilename 
  895.     "Writes a BottomDrawer representation of the receiver
  896.      (tracks only) on the named file."
  897.  
  898.     | file temp routeNumber |
  899.     file _ FileStream fileNamed: aFilename.
  900.     file text.
  901.     Cursor wait showWhile: [temp _ self tracks asSortedCollection].
  902.     routeNumber _ 0.
  903.     Cursor write showWhile: [
  904.         temp do: [:each |
  905.             routeNumber _ routeNumber + 1.
  906.             file nextPutAll: routeNumber printString.
  907.             each writeBottomDrawerOn: file]].
  908.     file close! !
  909. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  910.  
  911. PrintedCircuit class
  912.     instanceVariableNames: ''!
  913.  
  914.  
  915. !PrintedCircuit class methodsFor: 'instance creation'!
  916.  
  917. fromBottomDrawerFile: aFilename
  918.     "Create a new printed circuit board from the bottom drawer
  919.      file given."
  920.  
  921.     ^self new readBottomDrawerFile: aFilename!
  922.  
  923. new
  924.     "Create a new printed circuit board, with no pads or tracks."
  925.  
  926.     ^super new initialize! !
  927.  
  928. !PrintedCircuit class methodsFor: 'class initialization'!
  929.  
  930. initialize
  931.     "Initialize various default values."
  932.     "PrintedCircuit initialize."
  933.  
  934.     DefaultGrid _ 25@25.! !
  935.  
  936. PrintedCircuit initialize!
  937. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:35:49 pm'!
  938.  
  939. StandardSystemController subclass: #PcbTopController
  940.     instanceVariableNames: ''
  941.     classVariableNames: ''
  942.     poolDictionaries: ''
  943.     category: 'Printed-Circuits'!
  944. PcbTopController comment:
  945. 'Instances of me are used instead of StandardSystemController
  946. as the controller for the top view for a PrintedCircuitView  I change
  947. the functionality of some of the bluee button menu items.
  948. '!
  949.  
  950.  
  951. !PcbTopController methodsFor: 'menu messages'!
  952.  
  953. move
  954.     "Ask the user to designate a new origin position for the receiver's view.
  955.      Override here to prevent a complete redraw after a move."
  956.  
  957.     | labelForm labelOrigin viewBackground cursorPoint oldCursorPoint screenArea oldArea |
  958.     view deEmphasize.
  959.     sensor cursorPoint: view labelDisplayBox origin.
  960.     CacheBitmaps & view displayForm notNil
  961.       ifFalse: [
  962.         labelForm _ Form fromDisplay: (view labelDisplayBox).
  963.         view erase.
  964.         Cursor origin showWhile:
  965.             [labelForm follow: [sensor cursorPoint] while: [sensor noButtonPressed]].
  966.         labelOrigin _ sensor cursorPoint.
  967.         view align: view labelDisplayBox origin
  968.             with: labelOrigin.
  969.         view displayEmphasized]
  970.       ifTrue: [
  971.         Cursor origin showWhile: [
  972.             oldCursorPoint _ sensor cursorPoint.
  973.             oldArea _ view computeBoundingRectangleSet.
  974.  
  975.             [sensor noButtonPressed] whileTrue: [
  976.                 cursorPoint _ sensor cursorPoint.
  977.                 cursorPoint ~= oldCursorPoint ifTrue:
  978.                     [view align: oldCursorPoint with: cursorPoint.
  979.                      screenArea _ view computeBoundingRectangleSet.
  980.                      oldCursorPoint _ cursorPoint.
  981.                      view display.
  982.                      ScheduledControllers
  983.                         displayViewsThrough: (oldArea difference: screenArea)
  984.                         on: Display
  985.                         excluding: view.
  986.                      oldArea _ screenArea]]].
  987.         view displayEmphasized.
  988.         sensor cursorPoint: view displayBox center.
  989.         sensor waitNoButton]!
  990.  
  991. redisplay
  992.     "Re-display the current view only.  Override for PCB views."    
  993.  
  994.     self view displayBorder.
  995.     self view displaySubViews.
  996.     self view emphasize.
  997.     self view emphasizeLabel! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:38:34 pm'!
  998.  
  999. View subclass: #PrintedCircuitView
  1000.     instanceVariableNames: 'currentPadForm currentPadDiameter currentTrackWidth currentTrackForm currentPads currentTracks currentTransformation gridFlag '
  1001.     classVariableNames: 'DefaultWindow '
  1002.     poolDictionaries: ''
  1003.     category: 'Printed-Circuits'!
  1004. PrintedCircuitView comment:
  1005. 'I represent a view on a PrintedCircuit.  I maintain a cache of
  1006. the parts of the underlying model which can be seen at present
  1007. in instance variables currentPads and currentTracks.  I keep the current
  1008. Pad and Track sizes in currentPadForm/currentPadDiameter and
  1009. currentTrackForm/currentTrackWidth respectively.
  1010. '!
  1011.  
  1012.  
  1013. !PrintedCircuitView methodsFor: 'initialize-release'!
  1014.  
  1015. initialize
  1016.     "Initialize some instance variables."
  1017.  
  1018.     super initialize.
  1019.     self grid: false.        "Don't display the grid."!
  1020.  
  1021. release
  1022.  
  1023.     currentTracks release.
  1024.     currentPads release.
  1025.     currentPadForm release.
  1026.     currentTrackForm release.
  1027.     currentPadDiameter release.
  1028.     currentTrackWidth release. 
  1029.     currentTransformation release.
  1030.     gridFlag release.
  1031.     super release! !
  1032.  
  1033. !PrintedCircuitView methodsFor: 'accessing'!
  1034.  
  1035. grid
  1036.     "Answer whether the grid is to be displayed."
  1037.  
  1038.     ^gridFlag!
  1039.  
  1040. grid: aBoolean
  1041.     "The grid is to be displayed if aBoolean is true."
  1042.  
  1043.     gridFlag _ aBoolean!
  1044.  
  1045. nearestPadTo: aPoint 
  1046.     "Answer with the pad which is the nearest to aPoint in the currently 
  1047.      displayed pads, or nil if there is no sufficiently close pad."
  1048.  
  1049.     | grid box collection sortedCollection |
  1050.     grid _ self model grid scaleBy: self displayTransformation scale.
  1051.     box _ Rectangle origin: aPoint - grid corner: aPoint + grid.
  1052.     collection _ currentPads select: [:each | box containsPoint: each].
  1053.     collection size = 0 ifTrue: [^nil].
  1054.     sortedCollection _ collection asSortedCollection: [:first :second |
  1055.         (first - aPoint) abs r < (second - aPoint) abs r].
  1056.     ^collection first!
  1057.  
  1058. nearestTrackSegmentTo: aPoint 
  1059.     "Answer with the TrackSegment which is the nearest one
  1060.      to aPoint in the currently displayed collection of TrackSegments,
  1061.      or nil if there is no sufficiently close TrackSegment."
  1062.  
  1063.     | eachDistance closest closestDistance |
  1064.     closestDistance _ 7.        "Max distance - seems about right."
  1065.     currentTracks do: [:each |
  1066.         eachDistance _ aPoint dist:
  1067.             (aPoint pointNearestLine: each startPoint to: each endPoint).
  1068.         eachDistance < closestDistance ifTrue: [
  1069.             closestDistance _ eachDistance.
  1070.             closest _ each]].
  1071.     closestDistance < 7 ifTrue: [^closest] ifFalse: [^nil]! !
  1072.  
  1073. !PrintedCircuitView methodsFor: 'displaying'!
  1074.  
  1075. displayGrid
  1076.     "Check whether the grid should be displayed.  If so, display the
  1077.      grid associated with the model."
  1078.  
  1079.     self grid ifTrue: [
  1080.         (self model grid scaleBy: self displayTransformation scale) < (8@8)
  1081.           ifTrue: [Transcript cr; show: 'Scale too small to display grid.']
  1082.           ifFalse: [self reallyDisplayGrid]]!
  1083.  
  1084. displayPad: aPad
  1085.     "Display aPad.  Add it to the currently displayed pads."
  1086.  
  1087.     currentPadDiameter = aPad diameter ifFalse: [
  1088.         currentPadForm _ Form dotOfSize: aPad diameter.
  1089.         currentPadDiameter _ aPad diameter].
  1090.     currentPads add: aPad.
  1091.     currentPadForm                    
  1092.         displayOn: Display
  1093.         at: aPad position
  1094.         clippingBox: self insetDisplayBox
  1095.         rule: Form paint
  1096.         mask: Form black!
  1097.  
  1098. displayPads
  1099.     "Display the pads associated with the model."
  1100.  
  1101.     currentPadDiameter _ 0.
  1102.     currentPads do: [:each |
  1103.         (currentPadDiameter = each diameter)
  1104.         ifFalse: [
  1105.             currentPadForm _ Form dotOfSize: each diameter.
  1106.             currentPadDiameter _ each diameter].
  1107.         currentPadForm                    
  1108.             displayOn: Display
  1109.             at: each position
  1110.             clippingBox: self insetDisplayBox
  1111.             rule: Form paint
  1112.             mask: Form black]!
  1113.  
  1114. displayParts
  1115.     "Display the grid, pads and tracks associated with the model."
  1116.  
  1117.     self displayGrid.
  1118.     self displayPads.
  1119.     self displayTracks!
  1120.  
  1121. displayRubberBandFrom: startPoint to: endPoint 
  1122.     "Display a rubber-band line from the nearest 
  1123.      point to startPoint on the model's grid, to the nearest 
  1124.      point to endPoint on the model's grid.  Answer
  1125.      the real end point."
  1126.  
  1127.     ^self
  1128.         displayRubberBandFrom: startPoint
  1129.         to: endPoint
  1130.         onGrid: self model grid!
  1131.  
  1132. displayTrack: aTrackSegment.
  1133.     "Display aTrackSegment.  Add it to the currently displayed tracks."
  1134.  
  1135.     currentTrackWidth = aTrackSegment width ifFalse: [
  1136.         currentTrackForm _ Pen new defaultNib: aTrackSegment width.
  1137.         currentTrackForm frame: self insetDisplayBox.
  1138.         currentTrackWidth _ aTrackSegment width].
  1139.     currentTracks add: aTrackSegment.
  1140.     currentTrackForm place: aTrackSegment startPoint.
  1141.     currentTrackForm goto: aTrackSegment endPoint!
  1142.  
  1143. displayTracks
  1144.     "Display the track segments associated with the model."
  1145.  
  1146.     currentTrackWidth _ 0.
  1147.     currentTracks do: [:each |
  1148.         currentTrackWidth = each width
  1149.         ifFalse: [
  1150.             currentTrackForm _ Pen new defaultNib: each width.
  1151.             currentTrackForm frame: self insetDisplayBox.
  1152.             currentTrackWidth _ each width].
  1153.         currentTrackForm place: each startPoint.
  1154.         currentTrackForm goto: each endPoint]!
  1155.  
  1156. displayView
  1157.     "Recalculate the displayed pads and tracks, then display the model."
  1158.  
  1159.     (currentTransformation == self displayTransformation)    ifFalse: [
  1160.         Cursor wait showWhile: [
  1161.             currentPads _ nil.
  1162.             currentPads _ self doTransformation: self model pads.
  1163.             currentTracks _ nil.
  1164.             currentTracks _ self doTransformation: self model tracks.
  1165.             currentTransformation _ self displayTransformation]].
  1166.     self displayParts!
  1167.  
  1168. removePad: aPoint
  1169.     "Remove the displayed Pad at aPoint.  Remove it from the set
  1170.      of currently displayed pads."
  1171.  
  1172.     | oldPad form |
  1173.     oldPad _ self findOldPad: aPoint.
  1174.     currentPads remove: oldPad.
  1175.     self deleteDisplayedPad: oldPad.
  1176.     self restoreGridAt: aPoint!
  1177.  
  1178. removeTrack: anArray
  1179.     "Remove the TrackSegment indicated by anArray."
  1180.  
  1181.     | oldTrackSegment |
  1182.     oldTrackSegment _ self findOldTrack: anArray.
  1183.     currentTracks remove: oldTrackSegment.
  1184.     self deleteDisplayedTrack: oldTrackSegment!
  1185.  
  1186. update: aParameter
  1187.     "The model has changed.  If aParameter is my model, redisplay
  1188.      all parts of the model from the currently displayed collection.  If aParameter
  1189.      is #all, completely re-create the display from the underlying model.
  1190.      If aParameter is #grid, just redisplay the parts necessary for the grid.
  1191.      If aParameter is a Pad, just display this pad.  If aParameter is a Point,
  1192.      remove the pad at this location.  If aParameter is a TrackSegment,
  1193.      just display this track.  If aParameter is an Array, remove the
  1194.      track represented by this array."
  1195.  
  1196.     (self topView containsPoint: self controller sensor cursorPoint) ifFalse: [
  1197.         self topView releaseSavedForms].
  1198.     aParameter == self model ifTrue: [^self display].
  1199.     aParameter == #all ifTrue: [
  1200.         currentTransformation _ nil.
  1201.         self topView releaseSavedForms.
  1202.         ^self display].
  1203.     aParameter == #grid ifTrue: [
  1204.         self grid ifTrue: [^self displayGrid] ifFalse: [^self display]].
  1205.     (aParameter isMemberOf: Pad) ifTrue: [
  1206.         ^self displayPad: (self displayTransform: aParameter)].
  1207.     (aParameter isMemberOf: Point) ifTrue: [
  1208.         ^self removePad: (self displayTransform: aParameter)].
  1209.     (aParameter isMemberOf: TrackSegment) ifTrue: [
  1210.         ^self displayTrack: (self displayTransform: aParameter)].
  1211.     (aParameter isMemberOf: Array) ifTrue: [
  1212.         ^self removeTrack: (Array
  1213.                 with: (self displayTransform: (aParameter at: 1))
  1214.                 with: (self displayTransform: (aParameter at: 2)))]! !
  1215.  
  1216. !PrintedCircuitView methodsFor: 'display transformation'!
  1217.  
  1218. displayTransform: anObject 
  1219.     "Override to use truncation rather than rounding."
  1220.  
  1221.     ^(self displayTransformation applyTo: anObject) truncated! !
  1222.  
  1223. !PrintedCircuitView methodsFor: 'window access'!
  1224.  
  1225. setDefaultWindow
  1226.     "Set the receiver's window to be the default size."
  1227.  
  1228.     self window: DefaultWindow viewport: Display boundingBox!
  1229.  
  1230. setNewWindow
  1231.     "Get a rectangle from the user, and change the receiver's window
  1232.      using this."
  1233.  
  1234.     | rect tr |
  1235.     rect _ Rectangle fromUser.
  1236.     tr _ (self inverseDisplayTransform: rect origin)
  1237.             corner: (self inverseDisplayTransform: rect corner).
  1238.     self window: tr viewport: Display boundingBox! !
  1239.  
  1240. !PrintedCircuitView methodsFor: 'controller access'!
  1241.  
  1242. defaultControllerClass
  1243.     ^PrintedCircuitController! !
  1244.  
  1245. !PrintedCircuitView methodsFor: 'private'!
  1246.  
  1247. deleteDisplayedPad: aPad
  1248.     "Overwrite the displayed version of aPad."
  1249.  
  1250.     | form |
  1251.     form _ Form dotOfSize: aPad diameter + 1.
  1252.     form white.
  1253.     form
  1254.         displayOn: Display
  1255.         at: aPad position
  1256.         clippingBox: self insetDisplayBox
  1257.         rule: Form over
  1258.         mask: Form black!
  1259.  
  1260. deleteDisplayedTrack: aTrackSegment
  1261.     "Overwrite the displayed version of aTrackSegment"
  1262.  
  1263.     | pen |
  1264.     pen _ Pen new defaultNib: aTrackSegment width + 1.
  1265.     pen frame: self insetDisplayBox.
  1266.     pen white.
  1267.     pen combinationRule: Form over.
  1268.     pen place: aTrackSegment startPoint.
  1269.     pen goto: aTrackSegment endPoint!
  1270.  
  1271. displayRubberBandFrom: startPoint to: endPoint onGrid: aGrid
  1272.     "Display a rubber-band, XOR thin line from the nearest
  1273.      point to startPoint on aGrid, to the nearest point to
  1274.      endPoint on aGrid.  The line is constrained to be at a
  1275.      multiple of 45 degrees.  Answer with the real end point
  1276.      so located."
  1277.  
  1278.     | pen realEndPoint |
  1279.     pen _ Pen new combinationRule: Form reverse.
  1280.     pen frame: self insetDisplayBox.
  1281.     pen place: (self displayTransform: (startPoint grid: aGrid)).
  1282.     realEndPoint _ endPoint
  1283.         nearestTo45DegreeLineThrough: (startPoint grid: aGrid) onGrid: aGrid.
  1284.     pen goto: (self displayTransform: realEndPoint).
  1285.     ^realEndPoint!
  1286.  
  1287. doTransformation: aCollection
  1288.     "Answer with a transformed and sorted collection containing
  1289.      the elements in aCollection."
  1290.  
  1291.     | corner origin collection |
  1292.     corner _ self window corner.
  1293.     origin _ self window origin.
  1294.     collection _ aCollection reject:
  1295.         [:each | each refPoint > corner or: [each refPoint < origin]].
  1296.     ^(collection collect: [:each | self displayTransform: each])
  1297.         asSortedCollection: [:first :second | first size > second size]!
  1298.  
  1299. findOldPad: aPoint
  1300.     "Find the old displayed Pad corresponding to aPoint.  If not
  1301.      found, perform aBlock."
  1302.  
  1303.     | box |
  1304.     box _ Rectangle origin: (aPoint - (1@1)) corner: (aPoint + (2@2)).
  1305.     ^currentPads detect: [:each | box containsPoint: each position]!
  1306.  
  1307. findOldTrack: anArray 
  1308.     "Find the old displayed TrackSegment corresponding to anArray."
  1309.  
  1310.     | startBox endBox |
  1311.     startBox _ Rectangle
  1312.             origin: (anArray at: 1) - (1 @ 1)
  1313.             corner: (anArray at: 1) + (2 @ 2).
  1314.     endBox _ Rectangle
  1315.             origin: (anArray at: 2) - (1 @ 1)
  1316.             corner: (anArray at: 2) + (2 @ 2).
  1317.     ^currentTracks detect: [:each |
  1318.             ((startBox containsPoint: each startPoint)
  1319.                     and: [endBox containsPoint: each endPoint])
  1320.             or: [(startBox containsPoint: each endPoint)
  1321.                     and: [endBox containsPoint: each startPoint]]]!
  1322.  
  1323. reallyDisplayGrid
  1324.     "Actually display the grid."
  1325.  
  1326.     | form xStart xEnd yStart yEnd |
  1327.     form _ Form dotOfSize: 1.
  1328.     xStart _ (self window origin grid: self model grid) x.
  1329.     xEnd _ (self window corner grid: self model grid) x.
  1330.     yStart _ (self window origin grid: self model grid) y.
  1331.     yEnd _ (self window corner grid: self model grid) y.
  1332.     xStart to: xEnd by: self model grid x do: [:x |
  1333.         yStart to: yEnd by: self model grid y do: [:y |
  1334.             form
  1335.                 displayOn: Display
  1336.                 at: (self displayTransform: x@y)
  1337.                 clippingBox: self insetDisplayBox]]!
  1338.  
  1339. restoreGridAt: aPoint
  1340.     "If the grid is enabled, restore the grid point at aPoint."
  1341.  
  1342.     | form |
  1343.      self grid ifTrue: [
  1344.         form _ Form dotOfSize: 1.
  1345.         form
  1346.             displayOn: Display
  1347.             at: aPoint
  1348.             clippingBox: self insetDisplayBox]! !
  1349. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  1350.  
  1351. PrintedCircuitView class
  1352.     instanceVariableNames: ''!
  1353.  
  1354.  
  1355. !PrintedCircuitView class methodsFor: 'instance creation'!
  1356.  
  1357. open
  1358.     "Create and schedule a printed circuit editor on a new
  1359.      printed circuit board."
  1360.     "PrintedCircuitView open."
  1361.  
  1362.     self openOn: PrintedCircuit new!
  1363.  
  1364. openOn: aPrintedCircuit 
  1365.     "Create and schedule a new instance of me on aPrintedCircuit."
  1366.     "PrintedCircuitView openOn: TestPCB."
  1367.  
  1368.     | topView pcbView |
  1369.     topView _ StandardSystemView
  1370.                 model: aPrintedCircuit
  1371.                 label: 'Printed Circuit Editor'
  1372.                 minimumSize: 250@200.
  1373.     topView controller: PcbTopController new.
  1374.     pcbView _ self new model: aPrintedCircuit.
  1375.     pcbView borderWidth: 1.
  1376.     pcbView insideColor: Form white.
  1377.     pcbView setDefaultWindow.
  1378.     topView addSubView: pcbView.
  1379.     topView controller open!
  1380.  
  1381. openOnFile: aFilename
  1382.     "Create and schedule a new instance of me on a new printed
  1383.      circuit with a bottom drawer representation in the file given
  1384.      by aFilename."
  1385.     "PrintedCircuitView openOnFile: 'test.bd'."
  1386.  
  1387.     self openOn: (PrintedCircuit fromBottomDrawerFile: aFilename)! !
  1388.  
  1389. !PrintedCircuitView class methodsFor: 'class initialization'!
  1390.  
  1391. initialize
  1392.     "Initialize various default values."
  1393.     "PrintedCircuitView initialize."
  1394.  
  1395.     DefaultWindow _ -20@-20 extent: 5200@3000! !
  1396.  
  1397. !PrintedCircuitView class methodsFor: 'class access'!
  1398.  
  1399. defaultWindow: aRectangle
  1400.     "Make aRectangle the default window."
  1401.  
  1402.     DefaultWindow _ aRectangle! !
  1403.  
  1404. !PrintedCircuitView class methodsFor: 'examples'!
  1405.  
  1406. exampleWorkspace
  1407.     "Select and execute the expressions here to create and
  1408.      manipulate PrintedCircuits"
  1409.  
  1410.     "
  1411.     Smalltalk at: #TestPCB put: PrintedCircuit new.
  1412.  
  1413.     TestPCB readBottomDrawerFile: 'test.bd'.
  1414.     TestPCB readBottomDrawerFile: 'slim.pad.bd'.
  1415.  
  1416.     PrintedCircuitView openOn: TestPCB.
  1417.  
  1418.     TestPCB writeBottomDrawerOn: 'new.bd'.
  1419.  
  1420.     Smalltalk removeKey: #TestPCB.
  1421.     Smalltalk garbageCollect.
  1422.     "! !
  1423.  
  1424. PrintedCircuitView initialize!
  1425. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 July 1987 at 2:39:05 pm'!
  1426.  
  1427. MouseMenuController subclass: #PrintedCircuitController
  1428.     instanceVariableNames: 'currentTrackWidth currentPadSize redButtonFunction '
  1429.     classVariableNames: 'DefaultPadSize DefaultRedButtonFunction DefaultTrackWidth PCBYellowButtonMenu PCBYellowButtonMessages '
  1430.     poolDictionaries: ''
  1431.     category: 'Printed-Circuits'!
  1432. PrintedCircuitController comment:
  1433. 'I represent a controller for a PrintedCircuitView.  I maintain a
  1434. currentTrackWidth and a currentPadSize, which are used to
  1435. create new Pads and TrackSegments.  The instance variable
  1436. redButtonFunction indicates which operation (add/delete Pad/Track)
  1437. is performed by the red mouse button.
  1438. '!
  1439.  
  1440.  
  1441. !PrintedCircuitController methodsFor: 'initialize-release'!
  1442.  
  1443. initialize
  1444.     "Initialize the yellow button menus and the current pad
  1445.      and track sizes.  Initialize the red button action."
  1446.  
  1447.     super initialize.
  1448.     self
  1449.         yellowButtonMenu: PCBYellowButtonMenu
  1450.         yellowButtonMessages: PCBYellowButtonMessages.
  1451.  
  1452.     self trackWidth: DefaultTrackWidth.
  1453.     self padSize: DefaultPadSize.
  1454.     self redButtonFunction: DefaultRedButtonFunction! !
  1455.  
  1456. !PrintedCircuitController methodsFor: 'accessing'!
  1457.  
  1458. padSize
  1459.     "Answer with the current pad size."
  1460.  
  1461.     ^currentPadSize!
  1462.  
  1463. padSize: aNumber
  1464.     "Set the current pad size."
  1465.  
  1466.     currentPadSize _ aNumber!
  1467.  
  1468. redButtonFunction
  1469.     "Answer with the current red button function (a Symbol)."
  1470.  
  1471.     ^redButtonFunction!
  1472.  
  1473. redButtonFunction: aSymbol
  1474.     "Set the current red button function to a Symbol."
  1475.  
  1476.     redButtonFunction _ aSymbol!
  1477.  
  1478. trackWidth
  1479.     "Answer with the current track width."
  1480.  
  1481.     ^currentTrackWidth!
  1482.  
  1483. trackWidth: aNumber
  1484.     "Set the current track width."
  1485.  
  1486.     currentTrackWidth _ aNumber! !
  1487.  
  1488. !PrintedCircuitController methodsFor: 'menu messages'!
  1489.  
  1490. addPads
  1491.     "Set the current red button action to be adding Pads."
  1492.  
  1493.     self redButtonFunction: #addPads!
  1494.  
  1495. addTracks
  1496.     "Set the current red button action to be adding Tracks."
  1497.  
  1498.     self redButtonFunction: #addTracks!
  1499.  
  1500. changeGridSize
  1501.     "Prompt the user for a new grid size, and set this value as the
  1502.      current grid size."
  1503.  
  1504.     | aGridSize aNumber |
  1505.     aGridSize _ FillInTheBlank
  1506.                 request: ' New Grid Size? '
  1507.                 initialAnswer: self model grid x printString.
  1508.     aGridSize isEmpty ifFalse: [
  1509.         aNumber _ Number readFrom: (ReadStream on: aGridSize).
  1510.         self model grid: (aNumber@aNumber).
  1511.         self view grid ifTrue: [self model changed]]!
  1512.  
  1513. changePadSize
  1514.     "Prompt the user for a new pad size, and set this value as the
  1515.      current pad size."
  1516.  
  1517.     | aPadSize |
  1518.     aPadSize _ FillInTheBlank
  1519.             request: ' New Pad Size? '
  1520.             initialAnswer: (self padSize printString) .
  1521.     aPadSize isEmpty ifFalse: [
  1522.         self padSize: (Number readFrom: (ReadStream on: aPadSize))]!
  1523.  
  1524. changeTrackWidth
  1525.     "Prompt the user for a new track width, and set this value as the
  1526.      current track size."
  1527.  
  1528.     | aTrackWidth |
  1529.     aTrackWidth _ FillInTheBlank
  1530.             request: ' New Track Width? '
  1531.             initialAnswer: (self trackWidth printString).
  1532.     aTrackWidth isEmpty ifFalse: [
  1533.         self trackWidth: (Number readFrom: (ReadStream on: aTrackWidth))]!
  1534.  
  1535. changeWindow
  1536.     "Prompt the user for a new window."
  1537.  
  1538.     self view setNewWindow.
  1539.     self view update: self model!
  1540.  
  1541. defaultWindow
  1542.     "Set my view's window to its default value."
  1543.  
  1544.     self view setDefaultWindow.
  1545.     self view update: self model!
  1546.  
  1547. deletePads
  1548.     "Set the current red button action to be deleting Pads."
  1549.  
  1550.     self redButtonFunction: #deletePads!
  1551.  
  1552. deleteTracks
  1553.     "Set the current red button action to be deleting TrackSegments."
  1554.  
  1555.     self redButtonFunction: #deleteTracks!
  1556.  
  1557. toggleGrid
  1558.     "Toggle the displaying of the grid associated with my model."
  1559.  
  1560.     self view grid: (self view grid not).
  1561.     self view update: #grid! !
  1562.  
  1563. !PrintedCircuitController methodsFor: 'basic control sequence'!
  1564.  
  1565. controlInitialize
  1566.  
  1567.     Cursor crossHair show!
  1568.  
  1569. controlTerminate
  1570.  
  1571.     Cursor normal show! !
  1572.  
  1573. !PrintedCircuitController methodsFor: 'control defaults'!
  1574.  
  1575. isControlActive
  1576.  
  1577.     ^(view containsPoint: sensor cursorPoint) & sensor blueButtonPressed not! !
  1578.  
  1579. !PrintedCircuitController methodsFor: 'button activities'!
  1580.  
  1581. action: aSymbol at: aPoint
  1582.     "Perform the action indicated by aSymbol at aPoint."
  1583.  
  1584.     aSymbol == #addPads ifTrue: [^self addPadAt: aPoint].
  1585.     aSymbol == #deletePads ifTrue: [^self removePadAt: aPoint].
  1586.     aSymbol == #addTracks ifTrue: [^self addTrackAt: aPoint].
  1587.     aSymbol == #deleteTracks ifTrue: [^self removeTrackAt: aPoint]!
  1588.  
  1589. addPadAt: aPoint 
  1590.     "Add a Pad of the current size to the printed circuit represented 
  1591.      by my model."
  1592.  
  1593.     | newPad |
  1594.     newPad _ Pad
  1595.                 point: (self view inverseDisplayTransform: aPoint)
  1596.                 diameter: self padSize.
  1597.     self model changed: (self model addPad: newPad).
  1598.     self sensor waitNoButton!
  1599.  
  1600. addTrackAt: aPoint
  1601.     "Add a track of the current size to the collection of tracks
  1602.      represented by my model, starting at aPoint.  The end point
  1603.      is indicated by the user and is locked to the view's grid."
  1604.  
  1605.     | realStartPoint currentPoint realCurrentPoint endPoint newTrack |
  1606.     realStartPoint _ self view inverseDisplayTransform: aPoint.
  1607.     currentPoint _ self sensor cursorPoint.
  1608.     realCurrentPoint _ self view inverseDisplayTransform: currentPoint.
  1609.     self view
  1610.         displayRubberBandFrom: realStartPoint
  1611.         to: realCurrentPoint.
  1612.     [self sensor redButtonPressed] whileTrue: [
  1613.         (self sensor cursorPoint = currentPoint) ifFalse: [
  1614.             self view
  1615.                 displayRubberBandFrom: realStartPoint
  1616.                 to: realCurrentPoint.
  1617.             currentPoint _ self sensor cursorPoint.
  1618.             realCurrentPoint _ self view inverseDisplayTransform: currentPoint.
  1619.             self view
  1620.                 displayRubberBandFrom: realStartPoint
  1621.                 to: realCurrentPoint]].
  1622.     endPoint _ self view
  1623.         displayRubberBandFrom: realStartPoint
  1624.         to: realCurrentPoint.
  1625.     newTrack _ TrackSegment
  1626.         from: realStartPoint
  1627.         to: endPoint
  1628.         width: self trackWidth.
  1629.     self model changed: (self model addTrack: newTrack)!
  1630.  
  1631. redButtonActivity
  1632.     "Perform the current red button activity at the current input point."
  1633.  
  1634.     self sensor redButtonPressed ifTrue: [
  1635.         self action: self redButtonFunction at: self sensor cursorPoint]!
  1636.  
  1637. removePadAt: aPoint 
  1638.     "Remove the nearest Pad in the printed circuit represented 
  1639.      by my model.  Search in the view's currently displayed pads
  1640.      for the nearest one."
  1641.  
  1642.     | nearest pos |
  1643.     nearest _ self view nearestPadTo: aPoint.
  1644.     nearest isNil ifFalse: [
  1645.         pos _ (self view inverseDisplayTransform: nearest position)
  1646.                     grid: self model grid.
  1647.         self model removePad: pos.
  1648.         self model changed: pos].
  1649.     self sensor waitNoButton!
  1650.  
  1651. removeTrackAt: aPoint
  1652.     "Remove the nearest track segment to aPoint, provided it
  1653.      is close enough."
  1654.  
  1655.     | nearest anArray |
  1656.     nearest _ self view nearestTrackSegmentTo: aPoint.
  1657.     nearest isNil ifFalse: [
  1658.         anArray _ Array
  1659.         with:
  1660.          ((self view inverseDisplayTransform: nearest startPoint) grid: self model grid)
  1661.         with:
  1662.          ((self view inverseDisplayTransform: nearest endPoint) grid: self model grid).
  1663.         self model removeTrackSegment: anArray.
  1664.         self model changed: anArray].
  1665.     self sensor waitNoButton!
  1666.  
  1667. yellowButtonActivity
  1668.     "Change the cursor while the yellow button menu is active."
  1669.  
  1670.     Cursor normal showWhile: [super yellowButtonActivity]! !
  1671. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  1672.  
  1673. PrintedCircuitController class
  1674.     instanceVariableNames: ''!
  1675.  
  1676.  
  1677. !PrintedCircuitController class methodsFor: 'class initialization'!
  1678.  
  1679. initialize
  1680.     "Initialize the yellow button menus, and various default values."
  1681.  
  1682.     PCBYellowButtonMenu _ PopUpMenu
  1683.         labels: 'add pads\add tracks\delete pads\delete tracks\track width\pad size\grid size\toggle grid\zoom\un-zoom' withCRs
  1684.         lines: #(4 6 8).
  1685.     PCBYellowButtonMessages _
  1686.         #(addPads addTracks deletePads deleteTracks
  1687.            changeTrackWidth changePadSize changeGridSize toggleGrid
  1688.            changeWindow defaultWindow).
  1689.  
  1690.     DefaultPadSize _ Pad defaultDiameter.
  1691.     DefaultTrackWidth _ TrackSegment defaultWidth.
  1692.     DefaultRedButtonFunction _ #addPads.
  1693.  
  1694.     "PrintedCircuitController initialize."! !
  1695.  
  1696. PrintedCircuitController initialize!
  1697.  
  1698.